import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import reader.components.AbstractComponentRW;
import reader.components.ButtonRW;
import reader.components.DeviceRW;
import reader.components.FormRW;
import reader.components.FunctionRW;
import reader.components.IComponentRW;
import reader.components.LabelRW;
import reader.components.PanelRW;

import components.AbstractComponent;
import components.Button;
import components.Device;
import components.Form;
import components.Function;
import components.Label;
import components.Panel;

public class ClassMap {

    private final HashMap<Class<?>, Class<?>> rwClassMap = new HashMap<Class<?>, Class<?>>();

    private final HashMap<String, Class<?>> componentsClassMap = new HashMap<String, Class<?>>();

    private static ClassMap instance;

    private ClassMap() {
        rwClassMap.put(AbstractComponent.class, AbstractComponentRW.class);
        rwClassMap.put(Button.class, ButtonRW.class);
        rwClassMap.put(Device.class, DeviceRW.class);
        rwClassMap.put(Form.class, FormRW.class);
        rwClassMap.put(Function.class, FunctionRW.class);
        rwClassMap.put(Label.class, LabelRW.class);
        rwClassMap.put(Panel.class, PanelRW.class);

        componentsClassMap.put("AbstractComponent", AbstractComponent.class);
        componentsClassMap.put("Button", Button.class);
        componentsClassMap.put("Device", Device.class);
        componentsClassMap.put("Form", Form.class);
        componentsClassMap.put("Function", Function.class);
        componentsClassMap.put("Label", Label.class);
        componentsClassMap.put("Panel", Panel.class);

    }

    public static ClassMap getInstance() {
        if (instance == null) {
            instance = new ClassMap();
        }
        return instance;
    }

    public IComponentRW getComponentRW(Class clazz, Map opened) {
        Class rwClass = rwClassMap.get(clazz);

        try {
            //retorna uma instancia do contrutor que tenha como parametro um HashMap
            return (IComponentRW) rwClass.getDeclaredConstructors()[0].newInstance(new Object[] { opened });
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public AbstractComponent getComponent(String name, AbstractComponent parent) {
        //retorna a classe component a partir do seu nome
        Class componentClass = componentsClassMap.get(name);
        try {
            //pega o contrutor que tenha como parametro um Component
            Constructor contructor = componentClass.getDeclaredConstructor(new Class[] { AbstractComponent.class });
            //cria um vetor com o parametro que sera passado no contrutor instancia a classe
            return (AbstractComponent) contructor.newInstance(new Object[] { parent });
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public HashMap getComponetsClassMap() {
        return componentsClassMap;
    }
}